#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>	// OpenGL Graphics Utility Library
//#include "SimpleDraw.h"
#include "math.h"

// These variables control the current mode
int CurrentMode = 0;
const int NumModes = 5;

// These variables set the dimensions of the rectanglar region we wish to view.
double Xmin = 0.0, Xmax = 5.0;
double Ymin = 0.0, Ymax = 5.0;
double Zmin = 0.0, Zmax = 5.0;
GLdouble * points = NULL;
int count_points = 0;

static float angle=0.0,ratio;
static float x=0.0f,y=1.75f,z=5.0f;
static float lx=0.0f,ly=0.0f,lz=-1.0f;


void myKeyboardFunc( unsigned char key, int x, int y );

void drawScene(void);

void initRendering();
void resizeWindow(int w, int h);


void orientMe(float ang) {

		lx = sin(ang);
		lz = -cos(ang);
		glLoadIdentity();

		printf("angle = %f\n", ang);
		gluLookAt((Xmin +Xmax)/2 , (Ymin +Ymax)/2 +100 ,(Zmin+Zmax)/2 ,
			      (Xmin +Xmax)/2 + lx, (Ymin +Ymax)/2 + ly,(Zmin+Zmax)/2 + lz,
	  			  0.0f,1.0f,0.0f);
}

// glutKeyboardFunc is called below to set this function to handle
//		all "normal" ascii key presses.
// Only space bar and escape key have an effect.
void myKeyboardFunc( int key, int x, int y )
{
	switch ( key ) {

	case ' ':									// Space bar
		// Increment the current mode, and tell operating system screen needs redrawing
		CurrentMode = (CurrentMode+1)%NumModes;
		glutPostRedisplay();
		break;
	case GLUT_KEY_LEFT : 
		angle -= 1.01f;
		orientMe(angle);break;
	case GLUT_KEY_RIGHT : 
		angle +=1.01f;
		orientMe(angle);break;
	case 27:									// "27" is theEscape key
		exit(1);

	}
}


/*
 * drawScene() handles the animation and the redrawing of the
 *		graphics window contents.
 */
void drawScene(void)
{
	// Clear the rendering window

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


	gluLookAt((Xmin +Xmax)/2 , (Ymin +Ymax)/2 +100 ,(Zmin+Zmax)/2 ,
			      (Xmin +Xmax)/2 + lx, (Ymin +Ymax)/2 + ly,(Zmin+Zmax)/2 + lz,
	  			  0.0f,1.0f,0.0f);

	// Set drawing color to white
	glColor3f( 1.0, 1.0, 1.0 );		


		glBegin(GL_POINTS);{
				int i = 0;
				for(i = 0; i <count_points; ++i){
					glVertex3dv( points +(i*3) );
				}
		}glEnd();
		
	// Flush the pipeline.  (Not usually necessary.)
	glFlush();

}

// Initialize OpenGL's rendering modes
void initRendering()
{

	glEnable ( GL_DEPTH_TEST );

	// Uncomment out the first block of code below, and then the second block,
	//		to see how they affect line and point drawing.
	// The following commands should cause points and line to be drawn larger
	//	than a single pixel width.
	glPointSize(8);
	glLineWidth(5);

/*
	// The following commands should induce OpenGL to create round points and 
	//	antialias points and lines.  (This is implementation dependent unfortunately).
	glEnable(GL_POINT_SMOOTH);
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);	// Make round points, not square points
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);		// Antialias the lines
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
*/

}

// Called when the window is resized
//		w, h - width and height of the window in pixels.
void resizeWindow(int w, int h)
{
	double scale, center;
	double windowXmin, windowXmax, windowYmin, windowYmax;

	// Define the portion of the window used for OpenGL rendering.
	glViewport( 0, 0, w, h );	// View port uses whole window

	// Set up the projection view matrix: orthographic projection
	// Determine the min and max values for x and y that should appear in the window.
	// The complication is that the aspect ratio of the window may not match the
	//		aspect ratio of the scene we want to view.
	w = (w==0) ? 1 : w;
	h = (h==0) ? 1 : h;
	if ( (Xmax-Xmin)/w < (Ymax-Ymin)/h ) {
		scale = ((Ymax-Ymin)/h)/((Xmax-Xmin)/w);
		center = (Xmax+Xmin)/2;
		windowXmin = center - (center-Xmin)*scale;
		windowXmax = center + (Xmax-center)*scale;
		windowYmin = Ymin;
		windowYmax = Ymax;
	}
	else {
		scale = ((Xmax-Xmin)/w)/((Ymax-Ymin)/h);
		center = (Ymax+Ymin)/2;
		windowYmin = center - (center-Ymin)*scale;
		windowYmax = center + (Ymax-center)*scale;
		windowXmin = Xmin;
		windowXmax = Xmax;
	}
	// Now that we know the max & min values for x & y that should be visible in the window,
	//		we set up the orthographic projection.
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	//glOrtho( windowXmin, windowXmax, windowYmin, windowYmax, -1, 1 );
	gluPerspective(45,ratio,1,10000000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	gluLookAt((Xmin +Xmax)/2 , (Ymin +Ymax)/2 +100 ,(Zmin+Zmax)/2 ,
			      (Xmin +Xmax)/2 + lx, (Ymin +Ymax)/2 + ly,(Zmin+Zmax)/2 + lz,
	  			  0.0f,1.0f,0.0f);


}

int read_file(char *fname, GLdouble* numbers, int max_size){
	FILE * file;

	file = fopen(fname,"r");
	int i, j;
	int count = 0;
	char buff[10000];
	GLdouble * num;

	if(file==NULL) {
			printf("Error: can't open file.\n");
			return 1;
  	} else {
			printf("File opened successfully.\n");

			i = 0 ;    
			fgets(buff, 9999, file);
		printf("header: %s", buff);

		num = numbers;

		while(!feof(file) && count < max_size) { 
		  	/* loop through and store the numbers into the array */
		  	if(fscanf(file, "%lf,%lf,%lf,%s",num, num+1, num+2, buff)){
					num += 3;
					count += 3;

			}
		}


		fclose(file);
		/*
		num = numbers;
		for(i = 0; i< count; i+=3){
				printf("%lf,%lf,%lf\n", num[0], num[1], num[2]);
				num += 3;
		}
		*/
	}
	return count/3;
}

int find_min_max_points()
{
	GLdouble * mm;
	mm = (GLdouble*) malloc(6*sizeof*mm);
	
	
	int i;
	Xmin = Xmax = points[0];
	Ymin = Ymax = points[1];
	Zmin = Zmax = points[2];
	for(i = 0; i < count_points; i+=1){
			// finding min max X
			if(Xmin>points[i*3 + 0]){Xmin = points[i*3+0];};
			if(Xmax<points[i*3 + 0]){Xmax = points[i*3+0];};

			// finding min max y
			if(Ymin>points[i*3 + 1]){Ymin = points[i*3+1];};
			if(Ymax<points[i*3 + 1]){Ymax = points[i*3+1];};

			// finding min max z
			if(Zmin>points[i*3 + 2]){Zmin = points[i*3+2];};
			if(Zmax<points[i*3 + 2]){Zmax = points[i*3+2];};
	}
	return  0;
}

// Main routine
// Set up OpenGL, define the callbacks and start the main loop
int main( int argc, char** argv )
{
		points = (GLdouble*)malloc(atoi(argv[2])*sizeof*points);

		count_points = read_file(argv[1],points, atoi(argv[2]));
		GLdouble * num = points;
		int i = 0;
		
		find_min_max_points();

		printf("min X = %lf, max X = %lf\n", Xmin, Xmax);
		printf("min Y = %lf, max Y = %lf\n", Ymin, Ymax);
		printf("min Z = %lf, max Z = %lf\n", Zmin, Zmax);
		/*
		for(i = 0; i< count_points; i+=1){
				printf("%lf,%lf,%lf\n", num[0], num[1], num[2]);
				num += 3;
		}
*/
	glutInit(&argc,argv);

	// The image is not animated so single buffering is OK. 
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );

	// Window position (from top corner), and size (width and hieght)
	glutInitWindowPosition( 20, 60 );
	glutInitWindowSize( 360, 360 );
	glutCreateWindow( "SimpleDraw - Press space bar to toggle images" );

	// Initialize OpenGL as we like it..
	initRendering();

	// Set up callback functions for key presses
	//glutKeyboardFunc( myKeyboardFunc );			// Handles "normal" ascii symbols
	 glutSpecialFunc( myKeyboardFunc );		// Handles "special" keyboard keys

	// Set up the callback function for resizing windows
	glutReshapeFunc( resizeWindow );

	// Call this for background processing
	// glutIdleFunc( myIdleFunction );

	// call this whenever window needs redrawing
	glutDisplayFunc( drawScene );

	fprintf(stdout, "Press space bar to toggle images; escape button to quit.\n");
	

	// Start the main loop.  glutMainLoop never returns.
	glutMainLoop(  );

	return(0);	// This line is never reached.
}

